package com.neuedu.wemall.common.util;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import jakarta.servlet.http.HttpServletRequest;

import java.util.Date;


/**
 * @Author Scott
 * @Date
 * @Desc JWT工具类
 **/
public class JwtUtil {

    /**
     * Token有效期为15分钟
     */
    public static final long EXPIRE_TIME = 15 * 60 * 1000;


    /**
     * 检查用户token是否已失效、无效
     *
     * @param token      前端传入的token
     * @param username   用户名
     * @param secret     密钥
     * @param currentIP  客户端IP
     * @param redisUtils Redis工具类
     * @return
     */
    public static String verify(String token, String username, String secret, String currentIP, RedisUtils redisUtils) {
        String key = "member:login:token:" + username;
        Object value = redisUtils.get(key);
        if (value == null) {
            return "Token已失效";
        }
        String cacheToken = redisUtils.get(key).toString();
        //前端获取的token与缓存中的token不一致,即无效的token
        if (!token.equals(cacheToken)) {
            return "无效的token";
        }
        // 校验token有效性
        if (!verify(token, username, secret)) {
            //无效的token,原因:用户已修改账号信息.此时用户需要重新登录
            redisUtils.del(key);
            return "用户已修改账号信息,需要重新登录";
        }
        String ip = getIP(token);
        //检查token与客户端身份是否一致,防止一个客户端使用另外一个客户端的token
        if (StrUtil.isEmpty(ip)) {
            return "token身份异常";
        }
        if (!currentIP.equals(ip)) {
            return "token与客户端身份不一致";
        }
        return StrUtil.EMPTY;
    }

    /**
     * 校验token是否正确
     *
     * @param token  密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            // 根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
            String sign = getSign(token);
            // 效验签名
            DecodedJWT jwt = verifier.verify(sign);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 根据token获取sign
     *
     * @param token
     * @return
     */
    private static String getSign(String token) {
        String tokenJsonText = DES.decode(DES.KEY, token);
        JSONObject jo = JSON.parseObject(tokenJsonText);
        //获取签名
        String sign = jo.getString("sign");
        return sign;
    }

    /**
     * 根据token获取IP
     *
     * @param token
     * @return
     */
    public static String getIP(String token) {
        String tokenJsonText = DES.decode(DES.KEY, token);
        JSONObject jo = JSON.parseObject(tokenJsonText);
        //获取签名
        String ip = jo.getString("ip");
        return ip;
    }

    /**
     * 获得token中的用户名
     *
     * @return token中包含的用户名
     */
    public static String getUsername(String token) {
        try {
            String sign = getSign(token);
            DecodedJWT jwt = JWT.decode(sign);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            throw new IllegalArgumentException("解析tok`en失败");
        }
    }

    /**
     * 生成签名,15min后过期
     *
     * @param username 用户名
     * @param secret   用户的密码
     * @return 加密的token
     */
    public static String sign(String username, String secret, String ip) {
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附带username信息
        String sign = JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
        //签名信息中隐藏客户端IP
        JSONObject jo = new JSONObject();
        jo.put("sign", sign);
        jo.put("ip", ip);
        return DES.encode(DES.KEY, jo.toJSONString());
    }


    /**
     * 根据request中的token获取用户账号
     *
     * @param request
     * @return
     * @throws Exception
     */
    public static String getUserNameByToken(HttpServletRequest request) throws Exception {
        String accessToken = request.getHeader("X-Access-Token");
        String username = getUsername(accessToken);
        if (StrUtil.isEmpty(username)) {
            throw new Exception("未获取到用户");
        }
        return username;
    }

    /**
     * 获取 request 里传递的 token
     *
     * @param request
     * @return
     */
    public static String getTokenByRequest(HttpServletRequest request) {
        String token = request.getParameter("token");
        if (token == null) {
            token = request.getHeader("X-Access-Token");
        }
        return token;
    }

    public static void main(String[] args) {
        String token = "9A51DD2DB5FAD63C933CEA600E26F1BD71493BCC7DCBA9FA98629EFDBE596F91A4B068DA53B8E8F778ECB44EA87BB999B90B6BEA260FD9385B755F82B5927FE0620A0EBBE73FBD135832FE6673F0760F24F58086106A666D10E88431FA0C8D631DEA8EC9A4543993321A55F2351776FBA141013F9C55249759029F2E7F95A74C2A410B8F7A3C6054E673C777E58D66ED8F55F1C91AA85522D98BAA779B44FDE6";
       boolean result= verify(token, "admin", "123456");
        System.out.println(result);
        System.out.println(getUsername(token));
        System.out.println(getIP(token));
    }
}
